package com.ljc.listener;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.ljc.common.ErrorCode;
import com.ljc.constant.RedisConstant;
import com.ljc.exception.BusinessException;
import com.ljc.model.dto.UpdateUserInterfaceInfoDTO;
import com.ljc.model.entity.Order;
import com.ljc.model.enums.OrderStatusEnum;
import com.ljc.service.InnerUserInterfaceInfoService;
import com.ljc.service.OrderService;
import com.rabbitmq.client.Channel;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

import static com.ljc.constant.RabbitMqConstant.ORDER_SUCCESS_QUEUE_NAME;
import static com.ljc.constant.RedisConstant.LOCK_USER_STOCK;
import static com.ljc.constant.RedisConstant.USER_PURCHASE;


@Component
@Slf4j
public class AlipaySuccessListener {

    @Resource
    private OrderService orderService;
    @DubboReference
    private InnerUserInterfaceInfoService innerUserInterfaceInfoService;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private RedissonClient redissonClient;

    @GlobalTransactional(rollbackFor = Exception.class)
    @RabbitListener(queues = ORDER_SUCCESS_QUEUE_NAME)
    public void alipaySuccess(String orderNum, Message message, Channel channel) throws IOException {
        try {
            // 消息到达队列，就可以删掉了
            stringRedisTemplate.delete(RedisConstant.ORDER_PAY_SUCCESS_INFO + orderNum);
            // 看看这个消息消费过没有，防止重复消费
            String isUsed = stringRedisTemplate.opsForValue().get(RedisConstant.ORDER_PAY_RABBITMQ + orderNum);
            if (isUsed != null) {
                //消费过了
                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            }

            log.info("支付宝支付成功：{}", orderNum);
            if (StringUtils.isNotBlank(orderNum)) {

                // 修改订单状态
                orderService.update(new UpdateWrapper<Order>().eq("orderNumber", orderNum).set("status", OrderStatusEnum.DONE.getValue()));
                Order order = orderService.getOne(new QueryWrapper<Order>().eq("orderNumber", orderNum));
                String lockStock = stringRedisTemplate.opsForValue().get(USER_PURCHASE + orderNum);
                UpdateUserInterfaceInfoDTO updateUserInterfaceInfoDTO = new UpdateUserInterfaceInfoDTO();

                // 更新用户接口调用次数时，锁定用户，防止并发更新数据库出现问题
                Long userId = order.getUserId();
                Long interfaceId = order.getInterfaceId();

                // 1、创建锁对象
                RLock redisLock = redissonClient.getLock(LOCK_USER_STOCK + userId);
                // 2、尝试获取锁
                try {
                    redisLock.lock();
                    if (!redisLock.isLocked()) {
                        // 获取锁失败，直接返回失败或者重试
                        log.error("并发获取更新用户调用次数的锁失败！");
                        throw new BusinessException(ErrorCode.OPERATION_ERROR, "操作频繁！");
                    }
                    updateUserInterfaceInfoDTO.setUserId(userId);
                    updateUserInterfaceInfoDTO.setInterfaceId(interfaceId);
                    updateUserInterfaceInfoDTO.setLockNum(Long.valueOf(lockStock));
                    //更新用户接口调用次数
                    innerUserInterfaceInfoService.updateUserInterfaceInfo(updateUserInterfaceInfoDTO);
                    stringRedisTemplate.opsForZSet().incrementScore(RedisConstant.ANALYSIS_BUY_INTERFACE, String.valueOf(interfaceId), Double.parseDouble(lockStock));
                } finally {
                    // 3、释放锁
                    redisLock.unlock();
                }

            }
            // 消费成功，设置redis中的状态
            stringRedisTemplate.opsForValue().set(RedisConstant.ORDER_PAY_RABBITMQ + orderNum, "1", 30, TimeUnit.MINUTES);
            // 删除锁定的订单库存
            stringRedisTemplate.delete(USER_PURCHASE + orderNum);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            log.error("<======处理支付宝支付成功监听器出错======>");
            e.printStackTrace();
            stringRedisTemplate.delete(RedisConstant.ORDER_PAY_RABBITMQ + orderNum);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
        }
    }
}
